// Fill out your copyright notice in the Description page of Project Settings.


#include "Component/Recall.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "GameFramework/Character.h"
#include "Particles/ParticleSystemComponent.h"
#include "Particles/ParticleSystem.h"

URecall::URecall()
{
	PrimaryComponentTick.bCanEverTick = false;
	IsRecallActive = false;
	CanSetPos = true;
	DeltaTime = 0.05f;
	UpdateFrequency = 0.5f;
	RecallLength = 20;
	RecallSpeed = 3.f;
	TimePassage = 0.f;
}

void URecall::BeginPlay()
{
	Super::BeginPlay();
	Character = Cast<ACharacter>(GetOwner());
	check(Character);
	OriginalMaterials = Character->GetMesh()->GetMaterials();
	FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject(this, &URecall::RecallTimer);
	GetWorld()->GetTimerManager().SetTimer(RecallHandle, RespawnDelegate, UGameplayStatics::GetGlobalTimeDilation(Character) * DeltaTime, true);
}

void URecall::ActivateAbility(UMaterialInterface* SourceMaterial, UParticleSystem* LocalEmitter) {
	if (IsRecallActive || PositionArray.Num() <= 0) return;
	Counter = PositionArray.Num() - 1;
	LastActorTransform = Character->GetActorTransform();
	TimePassage = 0.f;
	Character->SetActorEnableCollision(false);
	for (int32 i = 0; i < OriginalMaterials.Num(); ++i) {
		Character->GetMesh()->SetMaterial(i, SourceMaterial);
	}
	Emitter = LocalEmitter;
	IsRecallActive = true;
}

void URecall::RecallTimer() {
	if (Character->GetVelocity() == FVector::ZeroVector) {
		IsRecallActive = false;
		return;
	}
	if (!IsRecallActive) {
		SavePlayerTransform();
	}
	else {
		SetPlayerTransform();
		if (Counter > 0) {
			Counter--;
			return;
		}
		PositionArray.Empty();
		IsRecallActive = false;
		Character->SetActorEnableCollision(true);
		for (int32 i = 0; i < OriginalMaterials.Num(); ++i) {
			Character->GetMesh()->SetMaterial(i, OriginalMaterials[i]);
		}
	}
}

void URecall::SavePlayerTransform() {
	if (GetWorld()->GetTimerManager().IsTimerActive(UniqueHandle)) return;
	FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject(this, &URecall::RecallPositions);
	GetWorld()->GetTimerManager().SetTimer(UniqueHandle, RespawnDelegate, UpdateFrequency, false);
}

void URecall::SetPlayerTransform() {
	TimePassage += DeltaTime;
	Character->SetActorTransform(UKismetMathLibrary::TLerp(LastActorTransform, PositionArray[Counter], FMath::Clamp<float>(TimePassage * RecallSpeed,0.f,1.f)));
	if (UKismetMathLibrary::NearlyEqual_TransformTransform(Character->GetActorTransform(), PositionArray[Counter], 150.f, 300.f, 5.f)) {
		TimePassage = 0.f;
		LastActorTransform = Character->GetActorTransform();
		UParticleSystemComponent* Temp = UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Emitter, LastActorTransform);
		check(Temp);
		FParticleSysParam TempP = FParticleSysParam();
		TempP.Actor = Character;
		TempP.ParamType = EParticleSysParamType::PSPT_Actor;
		TempP.Name = FName("VertSurfaceActor");
		Temp->InstanceParameters = TArray<FParticleSysParam>(&TempP, 1);
	}
}

void URecall::RecallPositions() {
	if (PositionArray.Num() >= RecallLength) {
		PositionArray.RemoveAt(0);
	}
	PositionArray.Add(Character->GetActorTransform());
	GetWorld()->GetTimerManager().ClearTimer(UniqueHandle);
}
